#include <string.h>
#include "ota_ble.h"
#include "ota_import.h"
#include "ota_verify.h"
#include "ota_hal_digest.h"

#define OTA_BLE_WAIT_TIME_MS    (10000) /*10s*/

#define BLE_OTA_VERIFY_IAMGE_MD5

static ota_ble_receive_t *ota_ble_queue    = NULL;
static unsigned char ota_ble_queue_ptr_in  = 0;
static unsigned char ota_ble_queue_ptr_out = 0;
static unsigned int image_information_buf_ptr = 0;
static unsigned char *image_information_buf = NULL;
static unsigned int image_inforation_buf_size = 0;
static ota_image_info image_tail_data_content;
static unsigned short image_crc16 = 0xffff;
static unsigned short image_crc16_bp = 0xffff;
static unsigned int image_has_recvd = 0;
static unsigned char image_head_is_get = 0;
static unsigned int off_bp = 0;
static ota_ble_global_dat_t g_ctx = {0};

ota_ble_global_dat_t* ota_ble_get_global_data_center(void)
{
    return &g_ctx;
}

unsigned int ota_ble_tail_get_len(unsigned int image_size, unsigned int tail_len)
{
    unsigned int tmp_len = 0;
    unsigned int want_len = 0;
    if(image_size - tail_len > 16) {
        tmp_len = image_size - tail_len;
        (tmp_len % 16 == 0) ? (want_len = tmp_len) : (want_len = tmp_len - tmp_len % 16);
    }
    return want_len;
}

static unsigned char *ota_ble_get_image_md5_value(void);

static unsigned short ota_ble_crc16_calculate(unsigned char const *p_data, unsigned int size, unsigned short const *p_crc)
{
    unsigned short crc = (p_crc == NULL) ? 0xFFFF : *p_crc;
    for (unsigned int i = 0; i < size; i++) {
        crc  = (unsigned char)(crc >> 8) | (crc << 8);
        crc ^= p_data[i];
        crc ^= (unsigned char)(crc & 0xFF) >> 4;
        crc ^= (crc << 8) << 4;
        crc ^= ((crc & 0xFF) << 4) << 1;
    }
    return crc;
}

static void ota_ble_init_image_crc16()
{
    image_crc16 = 0xffff;
    image_crc16_bp = 0xffff;
}

void ota_ble_calculate_image_crc16(unsigned char *data, unsigned int len)
{
    unsigned int erase_sector_size = 0;
    unsigned int tmp_len = 0;
    erase_sector_size = hal_flash_erase_sector_size();
    if (image_has_recvd % erase_sector_size + len >= erase_sector_size) {
        tmp_len = erase_sector_size - image_has_recvd % erase_sector_size;
        image_crc16 = ota_ble_crc16_calculate(data, tmp_len, &image_crc16);
        image_crc16_bp = image_crc16;
        image_crc16 = ota_ble_crc16_calculate(data + tmp_len, len - tmp_len, &image_crc16);
    }
    else {
        image_crc16 = ota_ble_crc16_calculate(data, len, &image_crc16);
    }
    image_has_recvd += len;
}

#ifdef BLE_OTA_VERIFY_IAMGE_MD5
static int ota_ble_calculate_image_md5(unsigned char *dgst, unsigned int data_offset, unsigned int size)
{
    int ret = -1;
    unsigned int   tmp_offset = 0;
    unsigned char  tmp_buf[32];
    unsigned int   read_len   = 0;
    unsigned int   total_len  = 0;
    ota_md5_context image_md5_ctx;
    if((size > 0) && (dgst != NULL)) {
        tmp_offset = data_offset;
        total_len = size;
        ota_md5_init(&image_md5_ctx);
        ota_md5_starts(&image_md5_ctx);
        while(tmp_offset < total_len) {
            (total_len - tmp_offset > sizeof(tmp_buf)) ?
            (read_len = sizeof(tmp_buf)) : (read_len = total_len - tmp_offset);
            ret = ota_read(&tmp_offset, tmp_buf, read_len);
            if(ret < 0) {
               break;
            }
            ota_md5_update(&image_md5_ctx, (const unsigned char *)tmp_buf, read_len);
        }
        if(ret >= 0) {
            ota_md5_finish(&image_md5_ctx, dgst);
            ota_md5_free(&image_md5_ctx);
        }
    }
    return ret;
}

static int ota_ble_verify_image()
{
    int ret = -1;
    unsigned char calculated_md5[16];
    unsigned char *src_md5 = NULL;
    ret = ota_ble_calculate_image_md5(&calculated_md5, 0x00, g_ctx.valid_fw_size - sizeof(ota_image_info));
    if(ret >= 0) {
        ret = -1;
        src_md5 = ota_ble_get_image_md5_value();
        if(src_md5 != NULL) {
            ret = strncmp(src_md5, calculated_md5, 16);
        }
    }
    return ret;
}
#endif

static int ota_ble_check_image_crc16()
{
    int ret = -1;
    (image_crc16 == g_ctx.crc) ? (ret = 0) : (ret = -1);
    return ret;
}

static unsigned int ota_ble_creat_receive_buf()
{
    if(ota_ble_queue != NULL) {
        return OTA_INIT_FAIL;
    }
    ota_ble_queue = ota_malloc(OTA_BLE_RECEIVE_BUF_NUMB * sizeof(ota_ble_receive_t));
    if(ota_ble_queue == NULL) {
        return OTA_INIT_FAIL;
    }
    memset(ota_ble_queue, 0x00, OTA_BLE_RECEIVE_BUF_NUMB * sizeof(ota_ble_receive_t));
    return OTA_SUCCESS;
}

static unsigned int ota_ble_init_receive_buf()
{
    unsigned int ret = 0;
    if(ota_ble_queue != NULL) {
        ota_free(ota_ble_queue);
    }
    ota_ble_queue = NULL;
    ret = ota_ble_creat_receive_buf();
    if(ret == OTA_SUCCESS) {
        ota_ble_queue_ptr_in  = 0;
        ota_ble_queue_ptr_out = 0;
    }
    return ret;
}

static void ota_ble_receive_data_product(unsigned char ota_cmd, unsigned char num_frame, unsigned char *buf, unsigned int len)
{
    if((ota_ble_queue != NULL) && (len <= OTA_BLE_REC_PER_FRAME_LEN)) {
        ota_ble_queue[ota_ble_queue_ptr_in].cmd = ota_cmd;
        ota_ble_queue[ota_ble_queue_ptr_in].len = len;
        ota_ble_queue[ota_ble_queue_ptr_in].num_frames = num_frame;
        if(buf != NULL) {
            memcpy(ota_ble_queue[ota_ble_queue_ptr_in].rec_buf, buf, len);
        }
        ota_ble_queue_ptr_in++;
        ota_ble_queue_ptr_in = ota_ble_queue_ptr_in % OTA_BLE_RECEIVE_BUF_NUMB;
    }
}

static unsigned int ota_ble_receive_data_consume(ota_ble_receive_t *out_queue)
{
    if(ota_ble_queue == NULL) {
        return OTA_INIT_FAIL;
    }
    if(ota_ble_queue_ptr_out != ota_ble_queue_ptr_in) {
        out_queue->cmd = ota_ble_queue[ota_ble_queue_ptr_out].cmd;
        out_queue->len = ota_ble_queue[ota_ble_queue_ptr_out].len;
        out_queue->num_frames = ota_ble_queue[ota_ble_queue_ptr_out].num_frames;
        memcpy(out_queue->rec_buf, ota_ble_queue[ota_ble_queue_ptr_out].rec_buf, out_queue->len);
        ota_ble_queue_ptr_out++;
        ota_ble_queue_ptr_out = ota_ble_queue_ptr_out % OTA_BLE_RECEIVE_BUF_NUMB;
    }
    else {
        return OTA_INIT_FAIL;
    }
    return OTA_SUCCESS;
}

static unsigned int ota_ble_creat_image_tail_data_buf()
{
    unsigned int ret = OTA_INIT_FAIL;
    if(image_information_buf == NULL) {
        image_inforation_buf_size = sizeof(ota_image_info) + 32;
        image_information_buf = ota_malloc(image_inforation_buf_size);
        if(image_information_buf != NULL) {
            ret = OTA_SUCCESS;
            memset(image_information_buf, 0x00, image_inforation_buf_size);
        }
        else {
            ret = OTA_INIT_FAIL;
        } 
    }
    return ret;
}

static void ota_ble_destroy_image_tail_data_buf()
{
    if(image_information_buf != NULL) {
        ota_free(image_information_buf);
    }
    image_information_buf = NULL;
}

static unsigned int ota_ble_get_image_data(unsigned char *buf, unsigned int len, unsigned char num_frames)
{
    unsigned int ret = OTA_INIT_FAIL;
    unsigned char *tmp_buf = image_information_buf + image_information_buf_ptr;
    if((image_information_buf_ptr + len) <= image_inforation_buf_size) {
        ret = OTA_SUCCESS;
        memcpy(tmp_buf, buf, len);
        g_ctx.frames_recvd += num_frames;
        g_ctx.bytes_recvd += len;
        image_information_buf_ptr += len;
    }
    return ret;
}

static unsigned char *ota_ble_get_image_md5_value()
{
    return image_tail_data_content.image_md5_value;
}

static unsigned int ota_ble_parse_image_info()
{
    unsigned int read_point = 0;
    unsigned int ret = OTA_INIT_FAIL;
    if(image_information_buf_ptr >= sizeof(ota_image_info)) {
        ret = OTA_SUCCESS;
        read_point = image_information_buf_ptr - sizeof(ota_image_info);
        memcpy((unsigned char*)&image_tail_data_content, image_information_buf + read_point, sizeof(ota_image_info));
        if ((image_tail_data_content.image_magic != OTA_BIN_MAGIC_APP) &&
            (image_tail_data_content.image_magic != OTA_BIN_MAGIC_KERNEL) &&
            (image_tail_data_content.image_magic != OTA_BIN_MAGIC_ALL)) {
            ret = OTA_DOWNLOAD_HEAD_FAIL;
        }
    }
    return ret;
}

static unsigned int ota_ble_check_version(char *version, unsigned char *p_data, unsigned char len)
{
    unsigned int ret = OTA_INIT_FAIL;
    int version_result = 0;
    unsigned char  l_data_new[OTA_VER_LEN + 1]; /* +1 for trailing zero */
    unsigned char  l_len;
    if((version != NULL) && (p_data != NULL) && (len > 7)) {
        l_len = len - sizeof(unsigned int) - sizeof(unsigned short) - 1;
        if(l_len > OTA_VER_LEN) {
            OTA_LOG_E("ver len too long");
            ret = OTA_UPGRADE_FW_SIZE_FAIL;
        }
        else {
            ret = OTA_SUCCESS;
            memcpy(l_data_new, p_data, l_len);
            l_data_new[l_len] = 0;
            version_result = strncmp(version, l_data_new, l_len);
            if (version_result == 0) {
                ret = OTA_TRANSPORT_VER_FAIL;
                OTA_LOG_E("ver same err!");
            }
        }
    }
    return ret;
}

static unsigned int ota_ble_update_data(unsigned char *buf, unsigned int len, unsigned char num_frames)
{
    unsigned int i = 0;
    unsigned short percent;
    int ret = OTA_SUCCESS;
    static unsigned short last_percent = 0;
    if((buf == NULL) || (len == 0)) {
        ret = OTA_INIT_FAIL;
        goto OTA_BLE_TRANS_ERR;
    }
    if ((len & 0x03) != 0) {
        ret = ota_ble_transport(OTA_BLE_CMD_ERROR, NULL, 0);
        if (ret != OTA_SUCCESS) {
            OTA_LOG_E("send err.\n");
        }
        ret = OTA_UPGRADE_FW_SIZE_FAIL;
        goto OTA_BLE_TRANS_ERR;
    }

    if (g_ctx.bytes_recvd == OTA_IMAGE_MAGIC_OFFSET) {
#ifdef BLE_OTA_SUPPORT_IMAGE_HEAD
        unsigned int bin_info_len = 0;
        ota_image_info bin_info;
        bin_info_len = sizeof(ota_image_info);
        if(len >= bin_info_len) {
            memcpy(&bin_info, buf, bin_info_len);
            if (bin_info.image_magic != OTA_BIN_MAGIC_ALL) {
                    ret = OTA_DOWNLOAD_HEAD_FAIL;
                    goto OTA_BLE_TRANS_ERR;
            }
            if(bin_info.image_size != g_ctx.valid_fw_size) {
                ret = OTA_UPGRADE_FW_SIZE_FAIL;
                goto OTA_BLE_TRANS_ERR;
            }
            ota_ble_calculate_image_crc16(buf, bin_info_len);
            buf += bin_info_len;
            len -= bin_info_len;
            g_ctx.bytes_recvd += bin_info_len;
        }
        else {
            ret = OTA_UPGRADE_FW_SIZE_FAIL;
            goto OTA_BLE_TRANS_ERR;
        }
#endif
    }
    if (ota_ble_write(&g_ctx.valid_bytes_recvd, (char *)buf, len) != 0) {
        ret = OTA_UPGRADE_WRITE_FAIL;
        goto OTA_BLE_TRANS_ERR;
    }
    ota_ble_calculate_image_crc16(buf, len);
    g_ctx.frames_recvd += num_frames;
    g_ctx.bytes_recvd += len;
    off_bp = g_ctx.bytes_recvd;
    percent = g_ctx.bytes_recvd * 100 / g_ctx.rx_fw_size; /* Ensure no overflow */
    if(percent < last_percent) {
        /*breakpoint need to clear last_percent*/
        last_percent = 0;
    }
    if ((percent - last_percent) >= 5) {
        OTA_LOG_I("===>%dB\t%d%% ...", g_ctx.bytes_recvd, percent);
        last_percent = percent;
    }
OTA_BLE_TRANS_ERR:
    return ret;
}

static int ota_ble_download_request(unsigned char *buffer, unsigned int len)
{
    int ret = 0;
    int resume = -1;
    unsigned char l_len = 0;
    unsigned int head_len = 0;
    unsigned int image_tail_len = 0;
    char version[64] = {0};

    if((buffer == NULL) || (len <  sizeof(unsigned int) + sizeof(unsigned short))) {
        return OTA_INIT_FAIL;
    }
    ret = ota_get_image_version(version);
    image_tail_len = sizeof(ota_image_info);
#ifdef BLE_OTA_SUPPORT_IMAGE_HEAD
    head_len = sizeof(ota_image_info);
#endif
    ret = ota_ble_check_version(ota_hal_version(0, 0), buffer, len);
    if (ret == 0) {
        if(memcmp(version, buffer, len) != 0) {
            image_head_is_get = 0;
            off_bp = 0;
        } else {
            if(image_head_is_get == 0) {
                off_bp = 0;
            }
        }
        ret = ota_update_image_version(buffer);
        l_len = len - sizeof(unsigned int) - sizeof(unsigned short);
        g_ctx.rx_fw_size = EXTRACT_U32(buffer + l_len);
        g_ctx.frames_recvd = 0;
        g_ctx.crc = EXTRACT_U16(buffer + l_len + sizeof(unsigned int));
        if(g_ctx.rx_fw_size > head_len) {
            g_ctx.valid_fw_size = g_ctx.rx_fw_size - head_len;
        } else {
            return OTA_UPGRADE_FW_SIZE_FAIL;
        }
        if(image_head_is_get == 0) {
            g_ctx.bytes_recvd = ota_ble_tail_get_len(g_ctx.rx_fw_size, image_tail_len);
            if(g_ctx.bytes_recvd == 0) {
                return OTA_DOWNLOAD_HEAD_FAIL;
            }
        }
        ota_update_image_size(g_ctx.valid_fw_size);
        ret = ota_ble_breakpoint_process(g_ctx.valid_fw_size, &off_bp);
        if(ret == 0) {
            g_ctx.valid_bytes_recvd = 0;
            if(off_bp > 0) {
                g_ctx.bytes_recvd = off_bp;
                g_ctx.valid_bytes_recvd = g_ctx.bytes_recvd - head_len;
                image_crc16 = image_crc16_bp;
                image_has_recvd = off_bp;
            }
        } else {
            return OTA_INIT_FAIL;
        }
    } else {
        ret = OTA_TRANSPORT_VER_FAIL;
    }
    return ret;
}

static int ota_ble_download_start(void)
{
    ota_ble_receive_t tmp_queue;
    ota_ble_state_t cur_ble_status;
    char *sys_ver = NULL;
    int ret = 0;
    unsigned char send_err  = 0;
    unsigned int timeout_cnt = 0;
    
    g_ctx.status = OTA_BLE_STATE_IDLE;
    g_ctx.task_ctrl = 1;
    g_ctx.task_flag = 1;
    while(1) {
        if(g_ctx.task_ctrl == 0) {
            goto OTA_BREEZE_OVER;
        }
        timeout_cnt++;
        if(timeout_cnt > OTA_BLE_WAIT_TIME_MS) {
            goto OTA_BREEZE_OVER;
        }
        if(ota_ble_receive_data_consume(&tmp_queue) == OTA_SUCCESS) {
            timeout_cnt = 0;
            if ((tmp_queue.cmd & OTA_BLE_CMD_TYPE_MASK) != OTA_BLE_CMD_TYPE_FW_UPGRADE) {
                OTA_LOG_E("cmd err");
            }
            else {
                cur_ble_status = g_ctx.status;
                printf("status = %d, tmp_queue.cmd = %d", cur_ble_status, tmp_queue.cmd);
                switch(cur_ble_status) {
                    case OTA_BLE_STATE_IDLE:
                        send_err = 1;
                        if (tmp_queue.cmd == OTA_BLE_CMD_FW_VERSION_REQ) { /*cmd=0x20*/
                            sys_ver = ota_hal_version(0, 0);
                            printf("sys_ver = %s\r\n", sys_ver);
                            ret = ota_ble_transport(OTA_BLE_CMD_FW_VERSION_RSP, sys_ver, strlen(sys_ver)) ;
                            if(ret != OTA_SUCCESS) {
                                OTA_LOG_E("send ver failed");
                                goto OTA_BREEZE_OVER;
                            }
                            send_err = 0;
                        }
                        else if (tmp_queue.cmd == OTA_BLE_CMD_FW_UPGRADE_REQ) { /*cmd=0x22*/
                            ret = ota_ble_download_request(tmp_queue.rec_buf, tmp_queue.len);
                            if (ret == OTA_SUCCESS) {
                                unsigned char ack = 1;
                                ret = ota_ble_transport(OTA_BLE_CMD_FW_UPGRADE_RSP, &ack, 1);
                                if (ret == OTA_SUCCESS) {
                                    unsigned char tmp_status = image_head_is_get;
                                    (tmp_status == 0) ? (g_ctx.status = OTA_BLE_STATE_RECEIVER_HEADER) :
                                            (g_ctx.status = OTA_BLE_STATE_RECEIVE);
                                    send_err = 0;
                                }
                            }
                            else {
                                unsigned char ack = 0;
                                ret = ota_ble_transport(OTA_BLE_CMD_FW_UPGRADE_RSP, &ack, 1);
                                goto OTA_BREEZE_OVER;
                            }
                        }
                        break;
                    case OTA_BLE_STATE_RECEIVER_HEADER:
                        send_err = 1;
                        if (tmp_queue.cmd == OTA_BLE_CMD_FW_DATA) { /*cmd=0x2F*/
                            ret = ota_ble_get_image_data(tmp_queue.rec_buf, tmp_queue.len, tmp_queue.num_frames);
                            if(ret == OTA_SUCCESS) {
                                if(g_ctx.bytes_recvd >= g_ctx.rx_fw_size) {
                                    g_ctx.bytes_recvd = 0;
                                    off_bp = 0;
                                    ret = ota_ble_parse_image_info();
                                    if(ret != OTA_SUCCESS) {
                                        break;
                                    }
                                    image_head_is_get = 1;
                                    g_ctx.status = OTA_BLE_STATE_RECEIVE;
                                }
                                ret = ota_ble_send_bytes_received();
                                if(ret == OTA_SUCCESS) {
                                    send_err = 0;
                                }
                            }
                            else {
                                OTA_LOG_E("rece data failed");
                            }
                        }
                        else if (tmp_queue.cmd == OTA_BLE_CMD_FW_GET_INIT_FW_SIZE) { /*cmd=0x27*/

                            ret = ota_ble_send_bytes_received();
                            if(ret == OTA_SUCCESS) {
                                ota_ble_init_image_crc16();
                                ret = ota_ble_creat_image_tail_data_buf();
                                if(ret == OTA_SUCCESS) {
                                    image_information_buf_ptr = 0;
                                    send_err = 0;
                                }
                            }
                        }
                        break;
                    case OTA_BLE_STATE_RECEIVE:
                        send_err = 1;
                        if (tmp_queue.cmd == OTA_BLE_CMD_FW_DATA) { /*cmd=0x2F*/
                            ret = ota_ble_update_data(tmp_queue.rec_buf, tmp_queue.len, tmp_queue.num_frames);
                            if(ret == OTA_SUCCESS) {
                                if(g_ctx.bytes_recvd >= g_ctx.rx_fw_size) {
                                    off_bp = 0;
                                    g_ctx.status = OTA_BLE_STATE_FW_CHECK;
                                }
                                ret = ota_ble_send_bytes_received();
                                if(ret == OTA_SUCCESS) {
                                    send_err = 0;
                                }
                            }
                            else {
                                OTA_LOG_E("rece data failed");
                            }
                        }
                        else if (tmp_queue.cmd == OTA_BLE_CMD_FW_GET_INIT_FW_SIZE) { /*cmd=0x27*/
                            ret = ota_ble_send_bytes_received();
                            if(ret == OTA_SUCCESS) {
                                if(g_ctx.bytes_recvd >= g_ctx.rx_fw_size) {
                                    off_bp = 0;
                                    g_ctx.status= OTA_BLE_STATE_FW_CHECK;
                                }
                                send_err = 0;
                            }
                        }
                        break;
                    case OTA_BLE_STATE_FW_CHECK:
                        send_err = 1;
                        if (tmp_queue.cmd == OTA_BLE_CMD_FW_XFER_FINISH) { /*cmd=0x28*/
                            if(ota_ble_check_image_crc16() == 0) {
#ifdef BLE_OTA_VERIFY_IAMGE_MD5
                               if(ota_ble_verify_image() != 0) {
                                    OTA_LOG_E("verify md5 failed");
                                } else
#endif
                                {
                                    ota_boot_param_t ota_param = {0};
                                    ret = ota_read_parameter(&ota_param);
                                    ota_param.upg_flag = OTA_UPGRADE_ALL;
                                    if(ota_hal_boot(&ota_param) == 0) {
                                        ota_msleep(2000);
                                        unsigned char ack = 1;
                                        ret = ota_ble_transport(OTA_BLE_CMD_FW_CHECK_RESULT, &ack, 1);
                                        g_ctx.status = OTA_BLE_STATE_RESET_PREPARE;
                                        OTA_LOG_I("setboot over");
                                        send_err = 0;
                                    } else {
                                        OTA_LOG_E("setboot failed");
                                    }
                                }
                            }
                            if(send_err == 1) {
                                unsigned char ack = 0;
                                ret = ota_ble_transport(OTA_BLE_CMD_FW_CHECK_RESULT, &ack, 1);
                                OTA_LOG_E("image check failed");
                                ota_msleep(2000);
                                ota_reboot();
                            }
                        }
                        break;
                    case OTA_BLE_STATE_RESET_PREPARE:
                    case OTA_BLE_STATE_OFF:
                        send_err = 1;
                        break;
                    default:
                        break;
                }
                if(send_err) {
                    ret = ota_ble_transport(OTA_BLE_CMD_ERROR, NULL, 0);
                    if (ret != OTA_SUCCESS) {
                        OTA_LOG_E("send err.\n");
                    }
                    OTA_LOG_E("send err report");
                    goto OTA_BREEZE_OVER;
                }
            }
        }
        ota_msleep(1);
    }
OTA_BREEZE_OVER:
    if(timeout_cnt > OTA_BLE_WAIT_TIME_MS) {
        OTA_LOG_E("ota ble receive timeout!");
    }
    OTA_LOG_I("task over!");
    if(ota_ble_queue != NULL) {
        ota_free(ota_ble_queue);
    }
    ota_ble_queue = NULL;
    if(image_information_buf != NULL) {
        ota_free(image_information_buf);
    }
    image_information_buf = NULL;
    g_ctx.task_flag = 0;
    g_ctx.status = OTA_BLE_STATE_IDLE;
    return 0;
}

int ota_ble_download(unsigned char ota_cmd, unsigned char num_frame, unsigned char *buf, unsigned int len)
{
    int ret = 0;
    volatile unsigned char tm_cnt = 0;
    void *thread = NULL;
    if((g_ctx.status == OTA_BLE_STATE_IDLE) && (ota_cmd == OTA_BLE_CMD_FW_VERSION_REQ)) {
        if(g_ctx.task_flag == 1) {
            g_ctx.task_ctrl = 0;
            while(g_ctx.task_flag == 1) {
                ota_msleep(1);
                if(tm_cnt > 2) {
                    OTA_LOG_E("last task over failed\r\n");
                    return OTA_DOWNLOAD_INIT_FAIL;
                }
                tm_cnt++;
            }
            g_ctx.status = OTA_BLE_STATE_IDLE;
        }
        if(ota_ble_init_receive_buf() != OTA_SUCCESS) {
            return OTA_DOWNLOAD_INIT_FAIL;
        }
        ota_ble_receive_data_product(ota_cmd, num_frame, buf, len);
        ret = ota_thread_create(&thread, (void *)ota_ble_download_start, (void *)NULL, NULL, 1024 * 4);
        if(ret < 0) {
            OTA_LOG_E("ota task creat failed");
            return OTA_DOWNLOAD_INIT_FAIL;
        }
    } else if((g_ctx.task_flag == 1) && (g_ctx.status != OTA_BLE_STATE_OFF)) {
        ota_ble_receive_data_product(ota_cmd, num_frame, buf, len);
    } else {
        g_ctx.task_ctrl = 0;
        g_ctx.status = OTA_BLE_STATE_IDLE;
        OTA_LOG_E("ota stus err");
    }
    return ret;
}
